unit uSearchEngines;

{$mode objfpc}{$H+}

interface

uses
    Classes, SysUtils, URIParser;

const
    // https://duckduckgo.com/?q=corewar
    cDuck: TURI = (
        Protocol: 'https';
        Username: '';
        Password: '';
        Host: 'duckduckgo.com';
        Port: 0;
        Path: '/';
        Document: '';
        Params: 'q=%s';
        Bookmark: '';
        HasAuthority: True;
        );

    cGoogle: TURI = (
        Protocol: 'http';
        Username: '';
        Password: '';
        Host: 'www.google.com';
        Port: 0;
        Path: '/';
        Document: 'search';
        Params: 'q=%s';
        Bookmark: '';
        HasAuthority: True;
        );

    cWikipedia: TURI = (
        Protocol: 'http';
        Username: '';
        Password: '';
        Host: 'en.wikipedia.org';
        Port: 0;
        Path: '/w/';
        Document: 'index.php';
        Params: 'search=%s';
        Bookmark: '';
        HasAuthority: True;
        );

    cLazarus: TURI = (
        Protocol: 'http';
        Username: '';
        Password: '';
        Host: 'wiki.lazarus.freepascal.org';
        Port: 0;
        Path: '/';
        Document: 'index.php';
        Params: 'search=%s';
        Bookmark: '';
        HasAuthority: True;
        );

    cIMDB: TURI = (
        Protocol: 'http';
        Username: '';
        Password: '';
        Host: 'www.imdb.com';
        Port: 0;
        Path: '/';
        Document: 'find';
        Params: 's=all&q=%s';
        Bookmark: '';
        HasAuthority: True;
        );

    cFS: TURI = (
        Protocol: 'http';
        Username: '';
        Password: '';
        Host: 'brb.to';
        Port: 0;
        Path: '/';
        Document: 'search.aspx';
        Params: 'search=%s';
        Bookmark: '';
        HasAuthority: True;
        );

    cEX: TURI = (
        Protocol: 'http';
        Username: '';
        Password: '';
        Host: 'www.ex.ua';
        Port: 0;
        Path: '/';
        Document: 'search';
        Params: 's=%s';
        Bookmark: '';
        HasAuthority: True;
        );

    //http://sourceforge.net/directory/os:windows/freshness:recently-updated/?q=abbrevia
    cSourceForge: TURI = (
        Protocol: 'http';
        Username: '';
        Password: '';
        Host: 'sourceforge.net';
        Port: 0;
        Path: '/directory/os:windows/freshness:recently-updated/';
        Document: 'search';
        Params: 'q=%s';
        Bookmark: '';
        HasAuthority: True;
        );

type

    { TSearchEngine }

    TSearchEngine = class
    private
        FDescription: string;
        FDocument: string;
        FHost: string;
        FKeyword: string;
        FName: string;
        FParams: string;
        FPath: string;
        procedure SetDescription(AValue: string);
        procedure SetDocument(AValue: string);
        procedure SetHost(AValue: string);
        procedure SetKeyword(AValue: string);
        procedure SetName(AValue: string);
        procedure SetParams(AValue: string);
        procedure SetPath(AValue: string);
    protected
    public
        // Returns full URL for search
        function GetSearchURL(const ARequest: string): string; virtual;

        // Character(s) that idetifies search engine
        property Keyword: string read FKeyword write SetKeyword;
        // Display name
        property Name: string read FName write SetName;
        // Description (for some unknown purposes)
        property Description: string read FDescription write SetDescription;

        property Host: string read FHost write SetHost;
        property Path: string read FPath write SetPath;
        property Document: string read FDocument write SetDocument;
        property Params: string read FParams write SetParams;
    end;

{
    Returns serch URL for given query if any.
    If not - returns query itself.
    There are several default engines:
    g - google
    w - wikipedia
    l - lazarus wiki
    imdb - IMDB
    Default engine is google
}
function GetSearchURL(const AQuery: string): string;

implementation

function GetSearchURL(const AQuery: string): string;

    function FillURI(const aURI: TURI; const aRequest: string): TURI;
    begin
        Result := aURI;
        if Pos('%s', aURI.Params) > 0 then
            Result.Params := Format(aURI.Params, [aRequest]);
        if Pos('%s', aURI.Bookmark) > 0 then
            Result.Bookmark := Format(aURI.Bookmark, [aRequest]);
    end;

var
    s, q: string;
    i: integer;
    u: TURI;
begin
    Result := Trim(AQuery);

    u := cDuck;

    // Check for searches
    i := Pos(' ', Result);
    if i > 0 then
    begin
        s := LowerCase(Copy(Result, 1, i - 1));
        q := Trim(Copy(Result, i + 1, Length(Result)));
        if s = 'g' then
            u := cGoogle
        else if s = 'w' then
            u := cWikipedia
        else if s = 'l' then
            u := cLazarus
        else if s = 'imdb' then
            u := cIMDB
        else if s = 'fs' then
            u := cFS
        else if s = 'ex' then
            u := cEX
        else if s = 'sf' then
            u := cSourceForge
        else
            q := Result;

        Result := EncodeURI(FillURI(u, q));
    end
    else
    if (Pos('.', Result) < 1) and (Pos(':', Result) < 1) then
    begin
        Result := EncodeURI(FillURI(u, Result));
    end;
end;

{ TSearchEngine }

procedure TSearchEngine.SetDescription(AValue: string);
begin
    if FDescription = AValue then
        Exit;
    FDescription := AValue;
end;

procedure TSearchEngine.SetDocument(AValue: string);
begin
    if FDocument = AValue then
        Exit;
    FDocument := AValue;
end;

procedure TSearchEngine.SetHost(AValue: string);
begin
    if FHost = AValue then
        Exit;
    FHost := AValue;
end;

procedure TSearchEngine.SetKeyword(AValue: string);
begin
    if FKeyword = AValue then
        Exit;
    FKeyword := AValue;
end;

procedure TSearchEngine.SetName(AValue: string);
begin
    if FName = AValue then
        Exit;
    FName := AValue;
end;

procedure TSearchEngine.SetParams(AValue: string);
begin
    if FParams = AValue then
        Exit;
    FParams := AValue;
end;

procedure TSearchEngine.SetPath(AValue: string);
begin
    if FPath = AValue then
        Exit;
    FPath := AValue;
end;

function TSearchEngine.GetSearchURL(const ARequest: string): string;
var
    u: TURI;
begin
    with u do
    begin
        Protocol := 'http';
        Username := '';
        Password := '';
        Host := FHost;
        Port := 0;
        Path := FPath;
        Document := FDocument;
        Params := Format(FParams, [ARequest]);
        Bookmark := '';
        HasAuthority := True;
    end;

    Result := EncodeURI(u);
end;

end.
